Test-driven implementation of the variant 26th decimal system
1, 2, 3, ... , 26, 27, 28, ... for a, b, c, ..., z, aa, ab, ... , z, aa, ab, ... to a, b, c, ..., z, aa, ab, ...
Since there is a space character other than a-z, of course it is not in 26th decimal, and since there is no space character in the middle of the number, it is not in 27th decimal, either.
I developed it based on the "fact" of test cases and their success or failure, rather than based on a vague "interpretation" that "it must be 26 decimal digits".
I think this test-driven story is rather interesting, so let's summarize it before I forget
complete form
code:python
def solve(N):
q = N
ret = ""
while True:
q, r = divmod(q - 1, 26)
ret = ascii_lowercaser + ret if q == 0:
print(ret)
return
I didn't write this code from the beginning.
At first I thought, "This problem is easy to test, so let's make it test-driven," so I put up a snippet that calls doctest. code:python
from string import ascii_lowercase
def solve(N):
"""
"""
def main():
N = int(input())
solve(N)
def _test():
import doctest
doctest.testmod()
if __name__ == "__main__":
import sys
argv = sys.argv
if len(sys.argv) == 1:
# no option
main()
_test()
else:
input = open(sys.argv1).buffer.readline First, write a test case
code:python
def solve(N):
"""
>> solve(1)
a
"""
Naturally, the test will fail.
code:python
$ python3 c2.py -t
**********************************************************************
File "c2.py", line 6, in __main__.solve
Failed example:
solve(1)
Expected:
a
Got nothing
**********************************************************************
1 items had failures:
1 of 1 in __main__.solve
***Test Failed*** 1 failures.
Write code that passes tests
code:python
def solve(N):
"""
>> solve(1)
a
"""
print(ascii_lowercaseN - 1) Run the test to confirm it is OK (doctest does not display anything when it is OK).
Add a test case
code:python
def solve(N):
"""
>> solve(1)
a
>> solve(27)
aa
"""
print(ascii_lowercaseN - 1) Naturally, the test will fail.
See what kind of failures you have.
I'm getting IndexError: string index out of range after reading the 27th of only 26 strings.
code:python
$ python3 c2.py -t
**********************************************************************
File "c2.py", line 8, in __main__.solve
Failed example:
solve(27)
Exception raised:
Traceback (most recent call last):
File ".../doctest.py", line 1329, in __run
compileflags, 1), test.globs)
File "<doctest __main__.solve1>", line 1, in <module> solve(27)
File "c2.py", line 11, in solve
print(ascii_lowercaseN - 1) IndexError: string index out of range
**********************************************************************
1 items had failures:
1 of 2 in __main__.solve
***Test Failed*** 1 failures.
Then let's just calculate the quotient divided by 26 and the remainder.
code:python
def solve(N):
"""
>> solve(1)
a
>> solve(27)
aa
"""
q, r = divmod(N - 1, 26)
The error message changed, and it was not a runtime error, but rather that the value output was wrong.
Let's fix this.
code:python
$ python3 c2.py -t
**********************************************************************
File "c2.py", line 8, in __main__.solve
Failed example:
solve(27)
Expected:
aa
Got:
a
**********************************************************************
1 items had failures:
1 of 2 in __main__.solve
***Test Failed*** 1 failures.
I haven't used the quotient I calculated earlier, so I'll use it anyway.
code:python
def solve(N):
"""
>> solve(1)
a
>> solve(27)
aa
"""
q, r = divmod(N - 1, 26)
if q == 0:
print(ret)
else:
print(ascii_lowercaseq + ret) Failure that it should be aa but it is ba (foreshadowing 1)
code:python
$ python3 c2.py -t
**********************************************************************
File "c2.py", line 8, in __main__.solve
Failed example:
solve(27)
Expected:
aa
Got:
ba
**********************************************************************
1 items had failures:
1 of 2 in __main__.solve
***Test Failed*** 1 failures.
The number was reduced by 1 to make it more consistent.
code:python
def solve(N):
"""
>> solve(1)
a
>> solve(27)
aa
"""
q, r = divmod(N - 1, 26)
if q == 0:
print(ret)
else:
print(ascii_lowercaseq - 1 + ret) Test OK
Add a new test case.
code:python
def solve(N):
"""
>> solve(1)
a
>> solve(27)
aa
>> solve(703)
aaa
"""
q, r = divmod(N - 1, 26)
if q == 0:
print(ret)
else:
print(ascii_lowercaseq - 1 + ret) Naturally, it will fail.
This error message IndexError: string index out of range is the one I saw earlier, let's fix it the same way.
code:python
$ python3 c2.py -t
**********************************************************************
File "c2.py", line 10, in __main__.solve
Failed example:
solve(703)
Exception raised:
Traceback (most recent call last):
File ".../doctest.py", line 1329, in __run
compileflags, 1), test.globs)
File "<doctest __main__.solve2>", line 1, in <module> solve(703)
File "c2.py", line 18, in solve
print(ascii_lowercaseq - 1 + ret) IndexError: string index out of range
**********************************************************************
1 items had failures:
1 of 3 in __main__.solve
***Test Failed*** 1 failures.
I copied and pasted the code I wrote earlier and modified it the same way.
code:python
def solve(N):
"""
>> solve(1)
a
>> solve(27)
aa
>> solve(703)
aaa
"""
q, r = divmod(N - 1, 26)
if q == 0:
print(ret)
else:
q, r = divmod(q - 1, 26)
ret = ascii_lowercaser + ret if q == 0:
print(ret)
else:
q, r = divmod(q - 1, 26)
ret = ascii_lowercaser + ret print(ret)
Test OK
The same thing continues after the fourth digit, so let's rewrite it using a loop.
code:python
def solve(N):
"""
>> solve(1)
a
>> solve(27)
aa
>> solve(703)
aaa
"""
q = N
while True:
q, r = divmod(q - 1, 26)
if q == 0:
print(ret)
break
Fail when rewritten and tested.
code:python
$ python3 c2.py -t
**********************************************************************
File "c2.py", line 8, in __main__.solve
Failed example:
solve(27)
Expected:
aa
Got:
a
**********************************************************************
File "c2.py", line 10, in __main__.solve
Failed example:
solve(703)
Expected:
aaa
Got:
a
**********************************************************************
1 items had failures:
2 of 3 in __main__.solve
***Test Failed*** 2 failures.
Forgot to extend the string. Correction.
code:python
def solve(N):
"""
>> solve(1)
a
>> solve(27)
aa
>> solve(703)
aaa
"""
q = N
ret = ""
while True:
q, r = divmod(q - 1, 26)
ret = ascii_lowercaser + ret if q == 0:
print(ret)
break
Test OK
Now submitted.
digression
I got ba in the middle (foreshadowing 1), but that was the correct 26th decimal.
Even in decimal notation, the first number to have two digits is 10, not 00.
This problem is different from the 26th decimal because it has to be aa, not ba.
I see people on Twitter trying to make an N-decimal library and lamenting that they couldn't implement the 26th decimal system correctly, but that's not what this problem is asking for in the first place.
Interpretation is skewed.
---
This page is auto-translated from /nishio/テストドリブンで変形26進法の実装. If you looks something interesting but the auto-translated English is not good enough to understand it, feel free to let me know at @nishio_en. I'm very happy to spread my thought to non-Japanese readers.